﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RuleOfReady.Core.DomainModels.Tiles;


namespace RuleOfReady.Core.DomainModels.Sets
{
    /// <summary>
    /// Object for storing a Partial Sequence (e.g. 2 3, as part of 2 3 4)
    /// </summary>
    public class MahjongPartialSequence : MahjongPossibleSet
    {

        #region IPossibleSet Properties

        /// <summary>
        /// (MahjongPossibleSet) The partial sequence of tiles this object represents
        /// </summary>
        public override IEnumerable<MahjongTile> Tiles { get; protected set; }

        /// <summary>
        /// (MahjongPossibleSet) Flag: is this partial set complete? (false)
        /// </summary>
        public override bool CompletedSet { get; protected set; }

        /// <summary>
        /// (MahjongPossibleSet) This tile needed to complete this partial sequence
        /// </summary>
        public override IEnumerable<MahjongTile> WaitingTiles { get; protected set; }

        #endregion




        /// <summary>
        /// Create a new partial sequence given a sequence, at a partial sequence in it
        /// </summary>
        /// <param name="partialSequence">the partial sequence of tiles</param>
        public MahjongPartialSequence(IEnumerable<MahjongSuitTile> partialSequence)
        {
            // guard checks
            IList<MahjongSuitTile> partSeqList = partialSequence.ToList();
            int difference = Math.Abs(partSeqList[0].SuitNumberInt - partSeqList[1].SuitNumberInt);
            if (difference > 2)
                throw new ArgumentException("tiles are too far apart to be part of a sequence", "partialSequence");
            if (difference == 0)
                throw new ArgumentException("tiles are a pair, not a partial sequence", "partialSequence");

            this.Tiles = partialSequence;
            this.WaitingTiles = this.BuildWaitingTiles();
            this.CompletedSet = false;
            
        }

        /// <summary>
        /// (MahjongPossibleSet) Add another tile to this partial sequence to make into a sequence
        /// </summary>
        /// <param name="addTile">Mahjong Tile to add</param>
        /// <returns>A Sequence, if the tile added is on the WaitingTiles list</returns>
        public override MahjongPossibleSet Add(MahjongTile addTile)
        {
            if (this.WaitingTiles.Contains(addTile))
                return new MahjongSequence(this.Tiles.Concat(new[] { addTile }).Cast<MahjongSuitTile>());
            else
                return null;
        }

        /// <summary>
        /// Returns a set of tiles that con be be added to this partial sequence to make it into a 
        /// Sequence
        /// </summary>
        /// <returns></returns>
        private IEnumerable<MahjongTile> BuildWaitingTiles()
        {
            IEnumerable<int> validNumbers = Enum.GetValues(typeof(MahjongSuitNumber)).Cast<int>();
            IList<MahjongSuitTile> partialSeq = this.Tiles.Cast<MahjongSuitTile>().OrderBy(tile => tile).ToList();
            MahjongSuitType suitType = partialSeq[0].SuitType;
            bool tilesAreTogether = partialSeq[0].SuitNumberInt + 1 == partialSeq[1].SuitNumberInt;

            if (tilesAreTogether)
            {
                int smaller = partialSeq[0].SuitNumberInt - 1;
                int larger = partialSeq[1].SuitNumberInt + 1;
                if (validNumbers.Contains(smaller))
                    yield return new MahjongSuitTile(suitType, smaller);
                if (validNumbers.Contains(larger))
                    yield return new MahjongSuitTile(suitType, larger);
            }
            else
            {
                MahjongSuitTile middleTile = new MahjongSuitTile(suitType, partialSeq[0].SuitNumberInt + 1);
                yield return middleTile;
            }
        }




    }
}
